#include "CallBacks.h"

FLT_PREOP_CALLBACK_STATUS CreatePreOperation(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{
    UNREFERENCED_PARAMETER(CompletionContext);

    FLT_PREOP_CALLBACK_STATUS retStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;

    do
    {
        if (!(Data->Iopb->Parameters.Create.Options & FILE_DELETE_ON_CLOSE)) break;

        if (!IsTargetFileByExtension(Data, L"txt")) break;

        if (FltGlobals.bDeny)
        {
            Data->IoStatus.Status = STATUS_ACCESS_DENIED;
            Data->IoStatus.Information = 0;
            retStatus = FLT_PREOP_COMPLETE;
        }
        else
        {
            BackUpFile(Data, FltObjects, TRUE);
            retStatus = FLT_PREOP_PENDING;
        }

    } while (FALSE);

    return retStatus;
}

FLT_PREOP_CALLBACK_STATUS WritePreOperation(
    _Inout_                         PFLT_CALLBACK_DATA Data,
    _In_                            PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_  PVOID* CompletionContext
)
{
    UNREFERENCED_PARAMETER(CompletionContext);

    NTSTATUS ntStatus;
    FLT_PREOP_CALLBACK_STATUS retStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
    BOOLEAN bDirectory;
    PFLT_FILE_NAME_INFORMATION lpFileNameInfo = NULL;
    UNICODE_STRING usFileName;

    do
    {
        ntStatus = FltIsDirectory(FltObjects->FileObject, FltObjects->Instance, &bDirectory);
        if (!NT_SUCCESS(ntStatus) || bDirectory) break;

        ntStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_QUERY_DEFAULT | FLT_FILE_NAME_NORMALIZED, &lpFileNameInfo);
        if (!NT_SUCCESS(ntStatus) || !lpFileNameInfo) break;

        ntStatus = FltParseFileNameInformation(lpFileNameInfo);
        if (!NT_SUCCESS(ntStatus)) break;

        RtlInitUnicodeString(&usFileName, L"abc.txt");
        if (0 == RtlCompareUnicodeString(&lpFileNameInfo->FinalComponent, &usFileName, TRUE))
        {
            Data->IoStatus.Status = STATUS_ACCESS_DENIED;
            Data->IoStatus.Information = 0;
            retStatus = FLT_PREOP_COMPLETE;
        }

    } while (FALSE);

    if (lpFileNameInfo)
        FltReleaseFileNameInformation(lpFileNameInfo);

    return retStatus;
}

FLT_PREOP_CALLBACK_STATUS SetInformationPreOperation(
    _Inout_                         PFLT_CALLBACK_DATA Data,
    _In_                            PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_  PVOID* CompletionContext
)
{
    UNREFERENCED_PARAMETER(CompletionContext);

    NTSTATUS ntStatus;
    FLT_PREOP_CALLBACK_STATUS retStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
    BOOLEAN bDirectory;
    BOOLEAN bBlock = FALSE;

    do
    {
        ntStatus = FltIsDirectory(FltObjects->FileObject, FltObjects->Instance, &bDirectory);
        if (!NT_SUCCESS(ntStatus) || bDirectory) break;

        switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass)
        {
        case FileRenameInformation:
        case FileRenameInformationEx:
            break;
        case FileRenameInformationBypassAccessCheck:
        case FileRenameInformationExBypassAccessCheck:
            break;
        case FileShortNameInformation:
            break;
        case FileDispositionInformation:
        case FileDispositionInformationEx:
            bBlock = TRUE;
            break;
        default:
            break;
        }

        if (!bBlock) break;

        if (!IsTargetFileByExtension(Data, L"txt")) break;

        if (FltGlobals.bDeny)
        {
            Data->IoStatus.Status = STATUS_ACCESS_DENIED;
            Data->IoStatus.Information = 0;
            retStatus = FLT_PREOP_COMPLETE;
        }
        else
        {
            BackUpFile(Data, FltObjects, FALSE);
        }

    } while (FALSE);

    return retStatus;
}